#include <iostream>
#include <memory>

//工厂方法：定义一个创建对象的接口，但是由子类来决定创建哪种对象，使用多个工厂分别生产指定的固定产品 
// 优点：  
// 1. 减轻了工厂类的负担，将某类产品的生产交给指定的工厂来进行 
// 2. 开闭原则遵循较好，添加新产品只需要新增产品的工厂即可，不需要修改原先的工厂类 
// 缺点：对于某种可以形成⼀组产品族的情况处理较为复杂，需要创建大量的工厂类. 


// class Fruit{
//     public:
//         virtual void name() = 0;
// };

// class Apple : public Fruit{
//     public:
//         void name() override{
//             std::cout << "我是苹果!\n";
//         }
// };

// class Banana : public Fruit{
//     public:
//         void name() override{
//             std::cout << "我是香蕉!\n";
//         }
// };

// class FruitFactory {
//     public:
//         virtual std::shared_ptr<Fruit> create() = 0;
// };
// class AppleFactory : public FruitFactory {
//     public:
//         virtual std::shared_ptr<Fruit> create() {
//             return std::make_shared<Apple>();
//         }
// };
// class BananaFactory : public FruitFactory {
//     public:
//         virtual std::shared_ptr<Fruit> create() {
//             return std::make_shared<Banana>();
//         }
// };

//  抽象工厂：围绕一个超级工厂创建其他工厂。每个生成的工厂按照工厂模式提供对象。 
// 思想：将工厂抽象成两层，抽象工厂 & 具体工厂子类， 在工厂子类种生产不同类型的子产品 
class Fruit {
    public:
        Fruit(){}
        virtual void show() = 0;
};
class Apple : public Fruit {
    public:
        Apple() {}
            virtual void show() {
            std::cout << "我是⼀个苹果" << std::endl;
        }
    private:
        std::string _color;
};
class Banana : public Fruit {
    public:
        Banana() {}
            virtual void show() {
            std::cout << "我是⼀个⾹蕉" << std::endl;
        }
};
class Animal {
    public:
        virtual void voice() = 0;
};
class Lamp: public Animal {
    public:
        void voice() { std::cout << "咩咩咩\n"; }
};
class Dog: public Animal {
    public:
        void voice() { std::cout << "汪汪汪\n"; }
};
class Factory {
    public:
        virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;
    virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};
class FruitFactory : public Factory {
    public:
        virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {
            return std::shared_ptr<Animal>();
        }
        virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {
            if (name == "苹果") {
                return std::make_shared<Apple>();
            }else if(name == "⾹蕉") {
                return std::make_shared<Banana>();
            }
            return std::shared_ptr<Fruit>();
        }
};
class AnimalFactory : public Factory {
    public:
        virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {
            return std::shared_ptr<Fruit>();
        }
        virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {
            if (name == "⼩⽺") {
                return std::make_shared<Lamp>();
            }else if(name == "⼩狗") {
                return std::make_shared<Dog>();
            }
            return std::shared_ptr<Animal>();
        }
};
class FactoryProducer {
    public:
        static std::shared_ptr<Factory> getFactory(const std::string &name) {
            if (name == "动物") {
                return std::make_shared<AnimalFactory>();
            }else {
                return std::make_shared<FruitFactory>();
            }
        }
};
